繼昨天講完type跟interface以後,相信大家都對這些型別有多一點點了解。
今天我們來看看Interface、type與物件的更多應用!
(有些時候你在interface或type當中看到的用法,或許可以交互拿來使用看看,像等等要提到的選擇性屬性,或唯讀屬性,是在兩者都能用的)
在JavaScript當中,我們有很多時間是在操作物件,或者是將物件放入函式中進行操作。在操作物件時,若我們只能很僵化的將type或interface固定成特定屬性的組合,未免有些難用。
這時,我們可以使用"?",將它後綴於選擇性的屬性名後:
interface FriedRice {
name: string
price: number
ingredients?: string[]
}
//沒有ingredients也不會報錯
const dish: FriedRice = {
name:"Yanzhou fried rice",
price:120,
}
但是,即便我們在interface當中設定某些屬性為選擇性的,我們仍然能在JavaScript當中去取用那個屬性,不過那個屬性如果不存在,他就會是undefined
。所以,這裡更理想的做法是:
//為可能不存在的值提供預設值,這用法滿常見的
function fry({ name, price, ingredients = ["egg"] }: FriedRice) {
console.log(`Dish is ${name} and it's $${price} dollars, it need ${ingredients} to make.`)
}
上面這個範例有個有趣的點,官方文件有特別寫出來,我們不能在被解構的語法中,為屬性增加型別註解
function fry({name: Rice, price: Price}){
console.log(name)
//Cannot find name 'name' Did you mean 'Rice'?
}
(這邊先不管Rice
跟Price
到底是什麼型別別名)
因為解構當中,如果屬性後出現冒號":",意思反而是:「請將name傳進來到當前的scope,並將其重新命名為Rice」,所以無法使用型別註解。
如果我們很確定一個屬性在物件當中,只能是唯讀而不能/不該被改變的,我們就能在interface的屬性名前加上readonly
interface Person {
readonly name: string
age: number
}
const John: Person = {
name: "John",
age: 18
}
// Cannot assign to 'name' because it is a read-only property.
John.name = "Allen"
但也不代表說他完全是不可變的,這點就跟在JavaScript當中,透過const
去宣告一個原始值跟物件的差別一樣,原始值無法被改變,但物件裡面的屬性/值可以。有這點概念,應該不會被衝康。
小結:今天先簡單講這兩個特性就好,不難且好記。
這邊需要提醒一下讀者,你不用到“完全搞懂”TypeScript才能開始使用TypeScript,從你最近開發的功能開始加上TypeScript,一定會越來越熟練的。